package com.yfqy.app.modules.customer.serviceimpl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.yfqy.app.configure.Idgenerator.SnowflakeIdGenerator;
import com.yfqy.app.constant.GeneralConstants;
import com.yfqy.app.constant.SystemConfigConstants;
import com.yfqy.app.domain.entity.Customer;
import com.yfqy.app.domain.entity.CustomerFundAccount;
import com.yfqy.app.domain.entity.IntegralRecord;
import com.yfqy.app.domain.entity.LeaderApply;
import com.yfqy.app.domain.mapper.CustomerFundAccountMapper;
import com.yfqy.app.domain.mapper.CustomerMapper;
import com.yfqy.app.domain.mapper.IntegralRecordMapper;
import com.yfqy.app.domain.mapper.LeaderApplyMapper;
import com.yfqy.app.enums.ApplyStatus;
import com.yfqy.app.enums.CustomerType;
import com.yfqy.app.enums.DefaultStatus;
import com.yfqy.app.enums.ErrorCode;
import com.yfqy.app.enums.IntegralType;
import com.yfqy.app.exception.BusinessException;
import com.yfqy.app.modules.customer.dto.ApplyForLeaderDTO;
import com.yfqy.app.modules.customer.dto.AvatarNicknameDTO;
import com.yfqy.app.modules.customer.service.CustomerService;
import com.yfqy.app.modules.customer.vo.CustomerDetailVO;
import com.yfqy.app.modules.customer.vo.CustomerFundAccountVO;
import com.yfqy.app.modules.system.dto.BindMobileRewardDTO;
import com.yfqy.app.modules.system.service.SystemConfigService;
import com.yfqy.app.util.AuthUserContext;
import com.yfqy.app.util.JSON;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

@Service
@Slf4j
public class CustomerServiceImpl implements CustomerService {

    @Resource
    private CustomerMapper customerMapper;
    @Resource
    private CustomerFundAccountMapper customerFundAccountMapper;
    @Resource
    private LeaderApplyMapper leaderApplyMapper;
    @Resource
    private SnowflakeIdGenerator idGenerator;
    @Resource(name = "defaultThreadPoolExecutor")
    private ThreadPoolExecutor threadPoolExecutor;
    @Resource
    private SystemConfigService systemConfigService;
    @Resource
    private IntegralRecordMapper integralRecordMapper;

    @Override
    public String applyForLeader(ApplyForLeaderDTO applyDTO) {
        log.info("开始处理分销商申请，客户ID: {}", applyDTO.getCustomerId());

        // 2. 检查用户资格
        checkUserEligibility(applyDTO.getCustomerId());

        // 3. 检查重复申请
        checkDuplicateApplication(applyDTO.getCustomerId());

        // 4. 保存申请记录
        saveApplicationRecord(applyDTO);

        // 5. 发送审核通知
        //sendAuditNotification(applyDTO);

        log.info("分销商申请处理完成，客户ID: {}", applyDTO.getCustomerId());

        return ErrorCode.SUCCESS.getMessage();
    }


    @Override
    public String updateAvatarNickname(AvatarNicknameDTO dto) {
        validateAvatarNicknameDTO(dto);
        // 获取用户ID并验证登录状态
        Long userId = getValidUserId();

        // 查询并验证用户信息
        getValidCustomer(userId);

        // 执行更新操作
        int update = customerMapper.updateAvatarNickname(dto.getNickname(), dto.getAvatar(), userId);
        if (update == 1) {
            return ErrorCode.SUCCESS.getMessage();
        }

        log.error("用户头像昵称更新失败，用户ID: {}", userId);
        throw new BusinessException(ErrorCode.SYSTEM_ERROR.getCode(), "用户信息更新失败");
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String bindPhoneNumber(String phoneNumber) {
        Long userId = getValidUserId();

        // 验证手机号格式
        validatePhoneNumber(phoneNumber);

        // 查询并验证用户信息
        Customer customer = getValidCustomer(userId);

        // 检查手机号是否已被其他用户绑定
        checkPhoneNumberAvailability(phoneNumber, userId);

        // 记录是否是首次绑定
        boolean isFirstBind = StringUtils.isBlank(customer.getPhone());

        // 更新手机号
        int update = customerMapper.updatePhoneNumber(phoneNumber, userId);
        if (update != 1) {
            log.error("绑定手机号失败，用户ID: {}, 手机号: {}", userId, phoneNumber);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR.getCode(), "绑定手机号失败");
        }

        log.info("手机号绑定成功，用户ID: {}, 手机号: {}", userId, phoneNumber);

        // 如果是首次绑定，触发后续操作
        if (isFirstBind) {
            afterBindPhoneNumber(userId, phoneNumber);
        }

        return ErrorCode.SUCCESS.getMessage();
    }

    @Override
    public CustomerDetailVO userInfo() {
        Long userId = AuthUserContext.getUserId();
        if (GeneralConstants.DEFAULT_USER_ID.equals(userId)) {
            throw new BusinessException(ErrorCode.USER_NOT_LOGIN);
        }
        Customer customer = customerMapper.selectByPrimaryKey(userId);
        CustomerDetailVO customerDetailVO = BeanUtil.toBean(customer, CustomerDetailVO.class);
        if (CustomerType.DISTRIBUTOR.getType() == customer.getIsLeader()) {
            CustomerFundAccount customerFundAccount = customerFundAccountMapper.selectByCustomerId(userId);
            CustomerFundAccountVO fundAccountVO = BeanUtil.toBean(customerFundAccount, CustomerFundAccountVO.class);
            customerDetailVO.setFundAccountVO(fundAccountVO);
        }
        return customerDetailVO;
    }

    /**
     * 验证手机号格式
     */
    private void validatePhoneNumber(String phoneNumber) {
        if (StringUtils.isBlank(phoneNumber)) {
            throw new BusinessException(ErrorCode.BAD_REQUEST.getCode(), "手机号不能为空");
        }

        boolean validPhoneNumber = phoneNumber.matches("^1[3-9]\\d{9}$");
        if (!validPhoneNumber) {
            throw new BusinessException(ErrorCode.BAD_REQUEST.getCode(), "手机号格式不正确");
        }
    }

    /**
     * 检查手机号是否可用
     */
    private void checkPhoneNumberAvailability(String phoneNumber, Long userId) {
        Customer existingByPhone = customerMapper.selectOneByPhone(phoneNumber);
        if (existingByPhone != null && !existingByPhone.getId().equals(userId)) {
            log.warn("手机号已被其他用户绑定，用户ID: {}, 手机号: {}, 绑定用户: {}",
                    userId, phoneNumber, existingByPhone.getId());
            throw new BusinessException(ErrorCode.PHONE_NUMBER_EXIST);
        }
    }

    /**
     * 首次绑定手机号后的处理
     */
    private void afterBindPhoneNumber(Long userId, String phoneNumber) {
        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {
                        log.info("事务提交成功，开始处理绑定手机号奖励，用户ID: {}, 手机号: {}", userId, phoneNumber);
                        // 使用线程池异步处理奖励发放
                        threadPoolExecutor.execute(() -> {
                            try {
                                sendPointsToUser(userId);
                            } catch (Exception e) {
                                log.error("发放绑定手机号奖励失败，用户ID: {}", userId, e);
                                // 这里可以添加补偿机制，如重试或记录到任务表
                            }
                        });
                    }

                    @Override
                    public void afterCompletion(int status) {
                        if (status != STATUS_COMMITTED) {
                            log.warn("事务未提交，取消绑定手机号奖励处理，用户ID: {}", userId);
                        }
                    }
                }
        );
    }


    /**
     * 发放积分奖励 - 使用CAS模式
     */
    protected void sendPointsToUser(Long userId) {
        try {
            // 重新查询用户最新信息
            Customer currentCustomer = customerMapper.selectByPrimaryKey(userId);
            if (currentCustomer == null) {
                log.error("用户不存在，无法发放奖励，用户ID: {}", userId);
                return;
            }

            // 获取奖励配置
            String configValue = systemConfigService.getConfigValue(
                    SystemConfigConstants.CONFIG_GROUP_INTEGRAL,
                    SystemConfigConstants.CONFIG_KEY_BIND_MOBILE_REWARD);

            if (StringUtils.isBlank(configValue)) {
                log.info("未配置绑定手机号奖励，用户ID: {}", userId);
                return;
            }

            BindMobileRewardDTO mobileRewardDTO = JSON.parse(configValue, BindMobileRewardDTO.class);
            if (mobileRewardDTO == null || mobileRewardDTO.getPoints() == null || mobileRewardDTO.getPoints() <= 0) {
                log.info("绑定手机号奖励配置无效，用户ID: {}", userId);
                return;
            }

            Integer rewardPoints = mobileRewardDTO.getPoints();

            // 使用CAS模式发放积分
            boolean rewardGranted = grantPointsWithCAS(userId, rewardPoints, currentCustomer.getPoints());

            if (rewardGranted) {
                log.info("绑定手机号奖励发放成功，用户ID: {}, 积分: {}", userId, rewardPoints);
            } else {
                log.warn("绑定手机号奖励发放失败，用户ID: {}", userId);
                // 可以添加重试机制或记录到补偿任务表
                retryGrantPointsWithCAS(userId, rewardPoints);
            }

        } catch (Exception e) {
            log.error("发放绑定手机号奖励异常，用户ID: {}", userId, e);
            // 这里可以记录到补偿任务表，由定时任务重试
            // recordCompensationTask(userId, "BIND_PHONE_REWARD");
        }
    }

    /**
     * 使用CAS模式发放积分
     * 原理：比较当前积分值，如果与预期值一致则更新
     */
    private boolean grantPointsWithCAS(Long userId, Integer addPoints, Integer expectedCurrentPoints) {
        // 计算新的积分值
        Integer newPoints = expectedCurrentPoints + addPoints;

        // CAS更新：只有当当前积分等于预期值时才更新
        int updated = customerMapper.updateUserPointsCAS(
                userId, newPoints, expectedCurrentPoints);

        if (updated == 1) {
            // 更新成功，插入积分记录
            insertIntegralRecord(userId, addPoints, newPoints);
            return true;
        }

        log.debug("CAS更新积分失败，用户ID: {}, 预期积分: {}, 新增积分: {}",
                userId, expectedCurrentPoints, addPoints);
        return false;
    }

    /**
     * CAS重试机制
     */
    private void retryGrantPointsWithCAS(Long userId, Integer addPoints) {
        final int maxRetry = 3;
        int retryCount = 0;

        while (retryCount < maxRetry) {
            try {
                // 每次重试前都重新查询最新数据
                Customer customer = customerMapper.selectByPrimaryKey(userId);
                if (customer == null) {
                    log.error("用户不存在，终止重试，用户ID: {}", userId);
                    return;
                }

                // 增加延迟，避免频繁重试
                if (retryCount > 0) {
                    Thread.sleep(50 * retryCount);
                }

                boolean success = grantPointsWithCAS(userId, addPoints, customer.getPoints());
                if (success) {
                    log.info("CAS重试发放积分成功，用户ID: {}, 重试次数: {}", userId, retryCount);
                    return;
                }

                retryCount++;
                log.debug("CAS重试发放积分失败，用户ID: {}, 重试次数: {}", userId, retryCount);

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.warn("CAS重试被中断，用户ID: {}", userId);
                break;
            } catch (Exception e) {
                log.error("CAS重试异常，用户ID: {}, 重试次数: {}", userId, retryCount, e);
                retryCount++;
            }
        }

        log.warn("CAS重试达到最大次数仍失败，用户ID: {}", userId);
    }

    /**
     * 插入积分记录
     */
    private void insertIntegralRecord(Long userId, Integer points, Integer currentBalance) {
        try {
            IntegralRecord record = new IntegralRecord();
            record.setId(idGenerator.nextId());
            record.setUserId(userId);
            record.setPoints(points);
            record.setCurrentBalance(currentBalance);
            record.setType(IntegralType.BIND_PHONE.getCode());
            record.setBusinessType(IntegralType.BIND_PHONE.name());
            record.setDescription(IntegralType.BIND_PHONE.getDesc());

            integralRecordMapper.insert(record);
        } catch (Exception e) {
            log.error("插入积分记录失败，用户ID: {}", userId, e);
            // 积分记录插入失败不影响主流程，但需要记录日志
        }
    }

    /**
     * 获取有效的用户信息
     */
    private Customer getValidCustomer(Long userId) {
        Customer customer = customerMapper.selectByPrimaryKey(userId);
        if (customer == null) {
            log.warn("用户不存在，用户ID: {}", userId);
            throw new BusinessException(ErrorCode.USER_NOT_EXIST);
        }
        if (customer.getStatus() == DefaultStatus.INVALID.getStatus()) {
            log.warn("用户状态无效，用户ID: {}", userId);
            throw new BusinessException(ErrorCode.USER_IS_INVALID);
        }
        return customer;
    }

    /**
     * 验证更新参数
     */
    private void validateAvatarNicknameDTO(AvatarNicknameDTO dto) {
        if (dto == null) {
            throw new BusinessException(ErrorCode.BAD_REQUEST.getCode(), "更新信息不能为空");
        }

        // 昵称验证
        if (StringUtils.isNotBlank(dto.getNickname())) {
            if (dto.getNickname().length() > 20) {
                throw new BusinessException(ErrorCode.BAD_REQUEST.getCode(), "昵称长度不能超过20个字符");
            }
        }

        // 头像URL验证
        if (StringUtils.isNotBlank(dto.getAvatar())) {
            if (dto.getAvatar().length() > 255) {
                throw new BusinessException(ErrorCode.BAD_REQUEST.getCode(), "头像URL长度过长");
            }
        }

        // 至少更新一个字段
        if (StringUtils.isBlank(dto.getNickname()) && StringUtils.isBlank(dto.getAvatar())) {
            throw new BusinessException(ErrorCode.BAD_REQUEST.getCode(), "至少需要更新昵称或头像其中一个字段");
        }
    }

    /**
     * 检查用户资格
     */
    private void checkUserEligibility(Long customerId) {
        // 检查用户是否存在
        Customer customer = customerMapper.selectByPrimaryKey(customerId);
        if (customer == null) {
            throw new BusinessException(ErrorCode.USER_NOT_EXIST);
        }

        // 检查用户状态是否正常
        if (customer.getStatus() != DefaultStatus.VALID.getStatus()) {
            throw new BusinessException(ErrorCode.USER_IS_INVALID);
        }

        // 检查是否已经是分销商
        if (customer.getIsLeader() == CustomerType.DISTRIBUTOR.getType()) {
            throw new BusinessException(ErrorCode.ALREADY_IS_LEADER);
        }

        // 检查是否有被驳回的申请（可根据业务需求调整）
        LeaderApply rejectedApply = leaderApplyMapper.findRecentRejectedApply(customerId);
        if (rejectedApply != null) {
            LocalDateTime rejectTime = rejectedApply.getAuditTime();
            if (rejectTime.isAfter(LocalDateTime.now().minusDays(7))) {
                throw new BusinessException(ErrorCode.LEADER_IS_REFUSED);
            }
        }
    }

    /**
     * 检查重复申请
     */
    private void checkDuplicateApplication(Long customerId) {
        List<Byte> pendingStatuses = Arrays.asList(
                ApplyStatus.PENDING.getCode(),
                ApplyStatus.UNDER_REVIEW.getCode()
        );

        LeaderApply pendingApply = leaderApplyMapper.findByCustomerIdAndStatusIn(customerId, pendingStatuses);
        if (pendingApply != null) {
            throw new BusinessException(ErrorCode.LEADER_APPLY_IS_EXITS);
        }
    }

    /**
     * 保存申请记录
     */
    private void saveApplicationRecord(ApplyForLeaderDTO applyDTO) {
        LeaderApply leaderApply = new LeaderApply();

        // 设置基本信息
        leaderApply.setId(idGenerator.nextId());
        leaderApply.setCustomerId(applyDTO.getCustomerId());
        leaderApply.setRealName(applyDTO.getRealName());
        leaderApply.setPhone(applyDTO.getPhone());
        leaderApply.setAddress(applyDTO.getAddress());
        leaderApply.setApplyReason(applyDTO.getApplyReason());
        int result = leaderApplyMapper.insert(leaderApply);
        if (result <= 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
        log.info("分销商申请记录保存成功，申请ID: {}", leaderApply.getId());
    }

//    /**
//     * 发送审核通知
//     */
//    private void sendAuditNotification(LeaderApplyDTO applyDTO) {
//        try {
//            AuditNotificationMessage message = new AuditNotificationMessage();
//            message.setApplyId(leaderApply.getId());
//            message.setCustomerId(applyDTO.getCustomerId());
//            message.setCustomerName(applyDTO.getRealName());
//            message.setApplyTime(LocalDateTime.now());
//
//            auditNotificationService.sendNotification(message);
//            log.info("审核通知发送成功，客户ID: {}", applyDTO.getCustomerId());
//        } catch (Exception e) {
//            // 通知发送失败不影响主流程，但需要记录日志
//            log.error("审核通知发送失败，客户ID: {}", applyDTO.getCustomerId(), e);
//        }
//    }


    /**
     * 获取有效的用户ID
     */
    private Long getValidUserId() {
        Long userId = AuthUserContext.getUserId();
        if (userId == null || GeneralConstants.DEFAULT_USER_ID.equals(userId)) {
            log.warn("用户未登录或登录状态异常");
            throw new BusinessException(ErrorCode.USER_NOT_LOGIN);
        }
        return userId;
    }
}
